// app_system_init.c
//
// Purpose: Implements the application's overall system initialization logic.
// This module defines the exact order and steps for bringing up all
// necessary hardware, drivers, and application components.
//
// System Thinking: The 'master script' for application startup.
// Module Thinking: Coordinates calls to other modules' init functions.
// Seamless Integration: Manages the binding of button events to LED actions.

#include "app_system_init.h"
#include "xil_printf.h" // For debug printing
#include "FreeRTOS.h" // For taskENTER_CRITICAL/taskEXIT_CRITICAL

// Include headers for all system modules to be initialized
#include "hw_gpio_hal.h"     // Hardware Abstraction Layer for GPIO
#include "button.h"          // Generic Button Driver
#include "app_buttons.h"     // Application-specific Button Management
#include "generic_led.h"     // Generic LED Driver


// FreeRTOS critical section macros for protecting shared application state
#define APP_ENTER_CRITICAL() taskENTER_CRITICAL()
#define APP_EXIT_CRITICAL()  taskEXIT_CRITICAL()


// =============================================================================
//  Application-Specific LED Configuration and State Management
// =============================================================================

// Predefined RGB colors for demonstration
const u8 RGB_RED[]    = {1, 0, 0};
const u8 RGB_GREEN[]  = {0, 1, 0};
const u8 RGB_BLUE[]   = {0, 0, 1};
const u8 RGB_YELLOW[] = {1, 1, 0};
const u8 RGB_CYAN[]   = {0, 1, 1};
const u8 RGB_MAGENTA[] = {1, 0, 1};
const u8 RGB_WHITE[]  = {1, 1, 1};
const u8 RGB_OFF[]    = {0, 0, 0};

// Array of RGB preset colors
const u8* const RGB_PRESETS[] = {
    RGB_RED, RGB_GREEN, RGB_BLUE, RGB_YELLOW, RGB_CYAN, RGB_MAGENTA, RGB_WHITE, RGB_OFF
};
#define NUM_RGB_PRESET_COLORS (sizeof(RGB_PRESETS) / sizeof(RGB_PRESETS[0]))

// --- State variables for LED behaviors (initial values adjusted for correct first click behavior) ---

// For BTN1 (EMIO GP LEDs pattern):
#define NUM_EMIO_GP_LEDS_CONST 4 // Assuming 4 general purpose EMIO LEDs
// 初始值设置为 NUM_EMIO_GP_LEDS_CONST - 1，以便第一次递增后变为0 (LD0)。
static u32 s_emio_gp_led_idx = NUM_EMIO_GP_LEDS_CONST - 1;

// For BTN2 (EMIO RGB LD5 color cycling):
// 初始值设置为 NUM_RGB_PRESET_COLORS - 1，以便第一次递增后变为0 (RED)。
static u32 s_rgb_ld5_color_idx = NUM_RGB_PRESET_COLORS - 1;

// For BTN3 (EMIO RGB LD6 blinking mode):
static u32 s_rgb_ld6_blink_mode = 0; // 0=Off, 1=Slow (Green), 2=Medium (Blue), 3=Fast (Red)
#define BLINK_MODE_OFF    0
#define BLINK_MODE_SLOW   1
#define BLINK_MODE_MEDIUM 2
#define BLINK_MODE_FAST   3


// =============================================================================
//  Application-Specific Button Click Callbacks (Interaction Logic)
// =============================================================================

/**
 * @brief Handles BTN0 click: Toggles MIO LD4 (monochrome LED).
 */
static void app_on_btn0_click(Button_t* button) {
    (void)button; // Suppress unused parameter warning
    GenericLed_t* led = GenericLed_GetByName("MIO_LD4");
    if (led) {
        // Track MIO_LD4's current logical state. Protected by critical section.
        static LedState_t current_state = LED_STATE_OFF;
        APP_ENTER_CRITICAL(); // Protect current_state
        current_state = (current_state == LED_STATE_ON) ? LED_STATE_OFF : LED_STATE_ON;
        APP_EXIT_CRITICAL();
        GenericLed_SetMonochromeState(led, current_state);
        xil_printf("BTN0 Clicked: MIO LD4 Toggled %s.\r\n", (current_state == LED_STATE_ON) ? "ON" : "OFF");
    }
}

/**
 * @brief Handles BTN1 click: Advances the pattern for EMIO General Purpose LEDs.
 */
static void app_on_btn1_click(Button_t* button) {
    (void)button; // Suppress unused parameter warning

    GenericLed_t* leds[] = {
        GenericLed_GetByName("EMIO_LD0"),
        GenericLed_GetByName("EMIO_LD1"),
        GenericLed_GetByName("EMIO_LD2"),
        GenericLed_GetByName("EMIO_LD3")
    };
    #define LOCAL_NUM_EMIO_GP_LEDS (sizeof(leds) / sizeof(leds[0])) // Re-define for local scope

    if (LOCAL_NUM_EMIO_GP_LEDS > 0) {
        APP_ENTER_CRITICAL(); // Protect s_emio_gp_led_idx

        // 1. 获取旧的索引
        u32 old_idx = s_emio_gp_led_idx;

        // 2. 递增到下一个LED的索引
        s_emio_gp_led_idx = (s_emio_gp_led_idx + 1) % LOCAL_NUM_EMIO_GP_LEDS;

        // 3. 关闭旧的LED
        if (leds[old_idx]) {
            GenericLed_SetMonochromeState(leds[old_idx], LED_STATE_OFF);
        }

        // 4. 打开新的LED
        if (leds[s_emio_gp_led_idx]) {
            GenericLed_SetMonochromeState(leds[s_emio_gp_led_idx], LED_STATE_ON);
        }
        APP_EXIT_CRITICAL();
    }
    xil_printf("BTN1 Clicked: EMIO GP LED pattern advanced. Current active LED: %s\r\n",
               (s_emio_gp_led_idx < LOCAL_NUM_EMIO_GP_LEDS && leds[s_emio_gp_led_idx]) ? GenericLed_GetName(leds[s_emio_gp_led_idx]) : "UNKNOWN");
}


/**
 * @brief Handles BTN2 click: Cycles through preset colors for EMIO RGB LD5.
 */
static void app_on_btn2_click(Button_t* button) {
    (void)button; // Suppress unused parameter warning
    GenericLed_t* led = GenericLed_GetByName("EMIO_LD5");
    if (led) {
        APP_ENTER_CRITICAL(); // Protect s_rgb_ld5_color_idx
        // 递增到下一个颜色索引
        s_rgb_ld5_color_idx = (s_rgb_ld5_color_idx + 1) % NUM_RGB_PRESET_COLORS;
        const u8* color = RGB_PRESETS[s_rgb_ld5_color_idx];
        APP_EXIT_CRITICAL();
        GenericLed_SetRGBColor(led, color[0], color[1], color[2]);
        xil_printf("BTN2 Clicked: EMIO RGB LD5 color changed to R%uG%uB%u.\r\n", color[0], color[1], color[2]);
    }
}

/**
 * @brief Handles BTN3 click: Cycles through blinking modes for EMIO RGB LD6.
 */
static void app_on_btn3_click(Button_t* button) {
    (void)button; // Suppress unused parameter warning
    GenericLed_t* led = GenericLed_GetByName("EMIO_LD6");
    if (led) {
        APP_ENTER_CRITICAL(); // Protect s_rgb_ld6_blink_mode
        // Advance to the next blink mode
        s_rgb_ld6_blink_mode = (s_rgb_ld6_blink_mode + 1) % (BLINK_MODE_FAST + 1); // +1 because BLINK_MODE_FAST is the highest index
        u32 current_blink_mode = s_rgb_ld6_blink_mode; // Make a local copy to use outside critical section
        APP_EXIT_CRITICAL();

        switch (current_blink_mode) {
            case BLINK_MODE_OFF:
                GenericLed_SetRGBBlink(led, 0, 0, 0, 0); // Stop blinking, turn off
                xil_printf("BTN3 Clicked: EMIO RGB LD6 blink mode OFF.\r\n");
                break;
            case BLINK_MODE_SLOW:
                GenericLed_SetRGBBlink(led, 1000, 0, 1, 0); // Green, 1s interval (500ms on, 500ms off)
                xil_printf("BTN3 Clicked: EMIO RGB LD6 blink mode SLOW (Green, 1000ms interval).\r\n");
                break;
            case BLINK_MODE_MEDIUM:
                GenericLed_SetRGBBlink(led, 500, 0, 0, 1); // Blue, 0.5s interval
                xil_printf("BTN3 Clicked: EMIO RGB LD6 blink mode MEDIUM (Blue, 500ms interval).\r\n");
                break;
            case BLINK_MODE_FAST:
                GenericLed_SetRGBBlink(led, 250, 1, 0, 0); // Red, 0.25s interval
                xil_printf("BTN3 Clicked: EMIO RGB LD6 blink mode FAST (Red, 250ms interval).\r\n");
                break;
        }
    }
}

/**
 * @brief Performs all necessary system and application module initializations.
 *        This includes hardware abstraction layers, generic drivers,
 *        application-specific modules, and binding their functionalities.
 * @return 0 on success, -1 on any critical initialization failure.
 */
int app_system_init(void)
{
    xil_printf( "App System Init: Starting module initializations...\r\n" );

    // 1. Initialize the Zynq PS GPIO controller through the Hardware Abstraction Layer (HAL).
    if (HAL_GPIO_Init() != XST_SUCCESS) {
        xil_printf("APP_SYSTEM_INIT HALT: GPIO controller initialization failed!\r\n");
        return -1;
    }

    // --- Define all LED configurations for the generic LED module ---
    const GenericLedConfig_t my_board_leds[] = {
        { .name = "MIO_LD4",    .type = LED_TYPE_MONOCHROME, .pin_r_or_mono = MIO_LD4_PIN,    .active_low = false },
        { .name = "EMIO_LD0",   .type = LED_TYPE_MONOCHROME, .pin_r_or_mono = EMIO_LD0_PIN,   .active_low = false },
        { .name = "EMIO_LD1",   .type = LED_TYPE_MONOCHROME, .pin_r_or_mono = EMIO_LD1_PIN,   .active_low = false },
        { .name = "EMIO_LD2",   .type = LED_TYPE_MONOCHROME, .pin_r_or_mono = EMIO_LD2_PIN,   .active_low = false },
        { .name = "EMIO_LD3",   .type = LED_TYPE_MONOCHROME, .pin_r_or_mono = EMIO_LD3_PIN,   .active_low = false },
        { .name = "EMIO_LD5",   .type = LED_TYPE_RGB,        .pin_r_or_mono = EMIO_LD5_R_PIN, .pin_g = EMIO_LD5_G_PIN, .pin_b = EMIO_LD5_B_PIN, .active_low = false },
        { .name = "EMIO_LD6",   .type = LED_TYPE_RGB,        .pin_r_or_mono = EMIO_LD6_R_PIN, .pin_g = EMIO_LD6_G_PIN, .pin_b = EMIO_LD6_B_PIN, .active_low = false },
    };
    #define NUM_MY_BOARD_LEDS (sizeof(my_board_leds) / sizeof(my_board_leds[0]))

    // 2. Initialize the generic LED control subsystem.
    if (generic_led_init(my_board_leds, NUM_MY_BOARD_LEDS) != 0) {
        xil_printf("APP_SYSTEM_INIT HALT: Generic LED control initialization failed!\r\n");
        return -1;
    }

    // 3. Initialize the application's button management subsystem.
    if (app_buttons_init() != 0) {
        xil_printf("APP_SYSTEM_INIT HALT: Application buttons initialization failed!\r\n");
        return -1;
    }

    // 4. Bind the button click event callbacks to the application-specific LED control handlers.
    //    These handlers (app_on_btnX_click) are defined within this module and
    //    interact with the generic LED driver.
    Button_SetClickCallback(Button_GetByName("BTN0"), app_on_btn0_click);
    Button_SetClickCallback(Button_GetByName("BTN1"), app_on_btn1_click);
    Button_SetClickCallback(Button_GetByName("BTN2"), app_on_btn2_click);
    Button_SetClickCallback(Button_GetByName("BTN3"), app_on_btn3_click);
    xil_printf("App System Init: Button click callbacks bound.\r\n");

    xil_printf( "App System Init: All modules initialized successfully.\r\n" );
    return 0; // Indicate success
}
